﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using Wen.Core;
using Wen.UI.Main;
using Wen.UI.NavigationElements;

namespace Wen.UI
{
	internal class NavigationViewModel : ViewModel
	{
		private readonly Viewport3D _scene;
		public Viewport3D Scene {
			get { return _scene; }
		}

		private IList<Light> _lights;

		private readonly IList<LightViewModelOfT> _lightViewModels = new ObservableCollection<LightViewModelOfT>();
		public IList<LightViewModelOfT> LightViewModels {
			get { return _lightViewModels; }
		}

		public NavigationViewModel(Viewport3D scene) {
			if (scene != null) {
				_scene = scene;
				if (_scene.IsLoaded)
					AddLights();
				else
					_scene.Loaded += SceneLoaded;
				_cameraViewModel = new CameraViewModel((ProjectionCamera)scene.Camera);
				IsShowingNavigator = true;
				IsTrackingProcess = true;
				XyzControlViewModelBase.DefaultStep = CalculateEfficientStep();
			}
			_selectProcessListViewModel = new ProcessListViewModel();
			_aboutViewModel = new AboutViewModel();
			CloseCommand = new SimpleCommand(CloseCommandImpl);
			MinimizeCommand = new SimpleCommand(MinimizeCommandImpl);
			CleanUpCommand = new SimpleCommand(CleanUpCommandImpl);
		}
		
		private double CalculateEfficientStep()
		{
			ProjectionCamera camera = (ProjectionCamera) Scene.Camera;
			return Math.Max(camera.Position.Z, 1) / 20;
		}

		private void CleanUpCommandImpl() {
			foreach (LightViewModelOfT lightViewModelOfT in _lightViewModels) {
				lightViewModelOfT.Cleanup();
			}
			if (CameraViewModel != null) {
				CameraViewModel.CameraRotationViewModel.ResetCommand.Execute(null);
				CameraViewModel.CameraPositionViewModel.ResetCommand.Execute(null);
				CameraViewModel.CameraDirectionViewModel.ResetCommand.Execute(null);
			}
		}

		private void MinimizeCommandImpl() {
			WindowState = WindowState.Minimized;
		}

		private void CloseCommandImpl() {
			NavigationWindow.Instance.CloseWindow();
		}

		void SceneLoaded(object sender, RoutedEventArgs e) {
			_scene.Loaded -= SceneLoaded;
			AddLights();
		}

		private void AddLights() {
			_lights = _scene.FindVisualChildren<Light>(null).ToList();
			foreach (Light light in _lights) {
				if (light is SpotLight) {
					_lightViewModels.Add(new SpotLightViewModel((SpotLight)light, _scene));
					continue;
				}
				if (light is PointLight) {
					_lightViewModels.Add(new PointLightViewModel((PointLight)light, _scene));
					continue;
				}
				if (light is AmbientLight) {
					_lightViewModels.Add(new AmbientLightViewModel((AmbientLight)light));
					continue;
				}
				if (light is DirectionalLight) {
					_lightViewModels.Add(new DirectionalLightViewModel((DirectionalLight)light, _scene));
					continue;
				}
			}
		}

		private readonly CameraViewModel _cameraViewModel;
		public CameraViewModel CameraViewModel {
			get { return _cameraViewModel; }
		}

		private readonly ProcessListViewModel _selectProcessListViewModel;
		public ProcessListViewModel SelectProcessListViewModel {
			get { return _selectProcessListViewModel; }
		}

		private readonly AboutViewModel _aboutViewModel;
		public AboutViewModel AboutViewModel
		{
			get { return _aboutViewModel; }
		}

		private WindowState _windowState;
		public WindowState WindowState {
			get { return _windowState; }
			set {
				_windowState = value;
				OnPropertyChanged("WindowState");
			}
		}

		public ICommand CloseCommand { get; set; }
		public ICommand MinimizeCommand { get; set; }
		public ICommand CleanUpCommand { get; set; }

		private bool _isShowingAbout;
		public bool IsShowingAbout {
			get { return _isShowingAbout; }
			set {
				if (_isShowingAbout == value)
					return;
				_isShowingAbout = value;
				OnPropertyChanged("IsShowingAbout");
				if (value) {
					IsShowingNavigator = false;
					IsShowingProcessList = false;
				}
				else {
					IsShowingNavigator = IsTrackingProcess;
					IsShowingProcessList = !IsTrackingProcess;
				}
			}
		}

		private bool _isShowingProcessList = true;
		public bool IsShowingProcessList {
			get { return _isShowingProcessList; }
			set {
				if (_isShowingProcessList == value)
					return;
				_isShowingProcessList = value;
				OnPropertyChanged("IsShowingProcessList");
				if (value)
					IsShowingAbout = false;
				IsShowingNavigator = !IsShowingAbout && !value;
			}
		}

		private bool _isShowingNavigator;
		public bool IsShowingNavigator {
			get { return _isShowingNavigator; }
			set {
				if (_isShowingNavigator == value)
					return;
				_isShowingNavigator = value;
				OnPropertyChanged("IsShowingNavigator");
				if (value)
					IsShowingAbout = false;
				IsShowingProcessList = !IsShowingAbout && !value;
			}
		}

		private bool _isTrackingProcess;
		public bool IsTrackingProcess {
			get { return _isTrackingProcess; }
			set {
				_isTrackingProcess = value;
				OnPropertyChanged("IsTrackingProcess");
			}
		}
	}
}
